package com.ruoyi.worker.domain.workAttendance;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.worker.constant.Constant;
import com.ruoyi.worker.domain.TimeShift;
import lombok.Data;
import lombok.ToString;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName AttendanceSalary
 * @Description 长期工工资
 * @Author leizhang
 * Date 2021/11/27 9:37 下午
 * @Version 1.0
 **/
@Data
@ToString
public class AttendanceSalary extends BaseEntity {
    private int id;
    private int salarySumId;
    /**
     * 长期工姓名
     **/
    @Excel(name = "长期工姓名")
    private String staffName;
    /**
     * 身份证
     **/
    @Excel(name = "身份证")
    private String idCard;
    /**
     * 班组id
     **/

    private String deptId;
    /**
     * 班组名称
     **/
    @Excel(name = "班组名称")
    private String deptName;
    /**
     * 职级id
     **/
    private int professionRankId;
    /**
     * 职级名称
     **/
    @Excel(name = "职级名称")
    private String professionRankName;
    /**
     * 组别
     **/
    @Excel(name = "组别名称")
    private String groupName;
    /**
     * 岗位id
     **/
    private int postId;
    /**
     * 岗位名称
     **/
    @Excel(name = "岗位名称")
    private String postName;
    /**
     * 月应出勤天数
     **/
    @Excel(name = "月应出勤天数")
    private int needAttendanceNumber;
    /**
     * 实际出勤天数
     **/
    @Excel(name = "实际出勤天数")
    private double actualAttendanceNumber;
    /**
     * 通班出勤天数
     **/
    @Excel(name = "通班出勤天数")
    private int dayNightAttendanceNumber;
    /**
     * 白班出勤天数
     **/
    @Excel(name = "白班出勤天数")
    private int dayAttendanceNumber;
    /**
     * 夜班出勤天数
     **/
    @Excel(name = "夜班出勤天数")
    private int nightAttendanceNumber;
    /**
     * 月综合工资标准
     **/
    @Excel(name = "月综合工资标准")
    private BigDecimal salaryStandard = new BigDecimal(0);
    /**
     * 标准工资
     **/
    @Excel(name = "标准工资")
    private BigDecimal basicSalary = new BigDecimal(0);
    /**
     * 基本工资
     **/
    @Excel(name = "基本工资")
    private BigDecimal jobBasicSalary = new BigDecimal(0);
    /**
     * 岗位补贴
     **/
    @Excel(name = "岗位补贴")
    private BigDecimal jobSubsidy = new BigDecimal(0);
    /**
     * 岗位工资
     **/
    @Excel(name = "岗位工资")
    private BigDecimal jobSalary = new BigDecimal(0);
    /**
     * 补发工资
     **/
    @Excel(name = "补发工资")
    private BigDecimal backPay = new BigDecimal(0);
    /**
     * 月度绩效
     **/
    @Excel(name = "月度绩效")
    private BigDecimal monthlyPerformance = new BigDecimal(0);
    /**
     * 住房补贴
     **/
    @Excel(name = "住房补贴")
    private BigDecimal housingAllowance = new BigDecimal(0);
    /**
     * 试用期系数
     **/
    @Excel(name = "试用期系数")
    private float probationPeriodCoefficient;
    /**
     * 全勤奖
     **/
    @Excel(name = "全勤奖")
    private BigDecimal perfectAttendanceAward = new BigDecimal(0);
    /**
     * 月度考核奖励
     **/
    @Excel(name = "月度考核奖励")
    private BigDecimal monthlyAssessmentRewards = new BigDecimal(0);
    /**
     * 应发工资
     * 有职级的：
     * 应发工资=（基本工资+岗位工资+岗位补贴+绩效+住宿补贴）*试用期系数*（实际出勤天数/月应出勤天数）+全勤奖+月度考核奖励+补发工资
     * <p>
     * 无职级的：
     * 应发工资=通班、晚班、白班的个数*对应的班次单价+全勤奖+岗位工资+补发工资
     **/
    @Excel(name = "应发工资")
    private BigDecimal payable = new BigDecimal(0);
    /**
     * 个人养老保险代扣
     **/
    @Excel(name = "个人养老保险代扣")
    private BigDecimal personalPension = new BigDecimal(0);
    /**
     * 个人医疗保险代扣
     **/
    @Excel(name = "个人医疗保险代扣")
    private BigDecimal personalMedical = new BigDecimal(0);
    /**
     * 个人失业保险代扣
     **/
    @Excel(name = "个人失业保险代扣")
    private BigDecimal individualUnemployment = new BigDecimal(0);
    /**
     * 社保之和 个人代扣社保合计=个人养老保险代扣+个人医疗保险代扣+个人失业保险代扣
     **/
    @Excel(name = "社保代扣总和")
    private BigDecimal sumSocialSecurity = new BigDecimal(0);
    /**
     * 月度考核扣款
     **/
    @Excel(name = "月度考核扣款")
    private BigDecimal assessmentDeduction = new BigDecimal(0);
    /**
     * 考勤扣款
     **/
    @Excel(name = "考勤扣款")
    private BigDecimal attendanceDeduction = new BigDecimal(0);
    /**
     * 工装扣款
     **/
    @Excel(name = "工装扣款")
    private BigDecimal toolingDeduction = new BigDecimal(0);
    /**
     * 实发工资
     * 有职级的：
     * 实发工资=应发工资-个人代扣-社保合计-月度考核扣款-考勤扣款-工装扣款
     * <p>
     * 无职级的：
     * 实发工资=应发工资-考勤扣款-工装扣款
     **/
    @Excel(name = "实发工资")
    private BigDecimal paidWages = new BigDecimal(0);

    /**
     * 考勤时间
     **/
    private String workTime;
    /**
     * 考勤记录
     **/
    private List<AttendanceDailyRecord> attendanceDailyRecords;
    /**
     * 岗位信息列表
     **/
    private List<SysDept> sysDept;
    /**
     * 班次信息
     **/
    private List<TimeShift> timeShiftList;

    /**
     * 排班记录
     **/
    private List<RzScheduleStaffPlan> staffPlans;
    /**
     * 白班工资
     **/
    private BigDecimal daySalary = new BigDecimal(0);
    /**
     * 夜班工资
     **/
    private BigDecimal nightSalary = new BigDecimal(0);
    /**
     * 通班工资
     **/
    private BigDecimal dayNightSalary = new BigDecimal(0);

    /**
     * 通班出勤天数旷工
     **/
    private int dayNightAbnormalAttendanceNumber;
    /**
     * 白班出勤天数旷工
     **/
    private int dayAbnormalAttendanceNumber;
    /**
     * 夜班出勤天数旷工
     **/
    private int nightAbnormalAttendanceNumber;

    @Excel(name = "备注")
    private String remark;

    /**
     * @param
     * @return int
     * @Description : 工资计算
     * @Author : leizhang
     * @Date 10:04 上午 2021/11/29
     **/
    public int calculateSalary() throws Exception {
        needAttendanceNumber = staffPlans.size();
        int absenteeismTime = 0;
        //1.考勤信息为空
        if (attendanceDailyRecords.isEmpty()) {
            return 0;
        }
        //社保合计
        sumSocialSecurity = personalPension.add(personalMedical).add(individualUnemployment);
        //2.考勤信息分组计算 {"班次":["":""，"":""]}
        //2-1.数据过去 去除非工作日的并且 出勤是正常的或者是旷工
        List<AttendanceDailyRecord> filterData = attendanceDailyRecords.parallelStream().filter(attendanceDailyRecord -> attendanceDailyRecord.getAttendanceType() == 1 && (attendanceDailyRecord.getAbnormalAttendance() == 3 || attendanceDailyRecord.getAbnormalAttendance() == 2)).collect(Collectors.toList());
        Map<String, List<AttendanceDailyRecord>> groupByShiftName = filterData.stream().collect(Collectors.groupingBy(AttendanceDailyRecord::getShiftName));
        //2-2 目前班次存在白班 夜班 通班 这里写死，因为规则是死的
        //班次混合阈值
        groupByShiftName.forEach((key, value) -> {
            int size = value.size();
            if ("白班".equals(key)) {
                dayAttendanceNumber = size;
            }
            if ("夜班".equals(key)) {
                nightAttendanceNumber = size;
            }
            if ("通班".equals(key)) {
                dayNightAttendanceNumber = size;
            }
        });
        //旷工记录
        List<AttendanceDailyRecord> attendanceRecords = attendanceDailyRecords.parallelStream().filter(attendanceDailyRecord -> attendanceDailyRecord.getAttendanceType() == 1 && attendanceDailyRecord.getAbnormalAttendance() == 2).collect(Collectors.toList());
        absenteeismTime = attendanceRecords.size();
        //迟到早退扣款
        int lateSum = attendanceBeLate(attendanceDailyRecords.parallelStream().filter(attendanceDailyRecord -> attendanceDailyRecord.getAttendanceType() == 1 && attendanceDailyRecord.getAbnormalAttendance() == 3).collect(Collectors.toList()));
        attendanceDeduction = assessmentDeduction.add(new BigDecimal(lateSum));
        //岗位分组
        Map<String, List<AttendanceDailyRecord>> groupByDeptName = attendanceDailyRecords.stream().collect(Collectors.groupingBy(AttendanceDailyRecord::getPostName));
        if (!StrUtil.isEmpty(professionRankName)) {
            //实际出勤天数，有职级的按通班算 白0.4 晚0.6
            actualAttendanceNumber = dayAttendanceNumber * 0.4 + nightAttendanceNumber * 0.6 + dayNightAttendanceNumber * 1;
            //全勤奖 通班个数大于13 才有全勤奖
            if (actualAttendanceNumber < 13) {
                perfectAttendanceAward = new BigDecimal(0);
            }
            //应发工资
            if (absenteeismTime > 0) {
                //有职级旷工扣减单月考核 和绩效
                monthlyPerformance = new BigDecimal(0);
                monthlyAssessmentRewards = new BigDecimal(0);
            }
            //有职级应出勤
            BigDecimal sumSalary = jobBasicSalary.add(jobSalary).add(jobSubsidy).add(monthlyPerformance).add(housingAllowance);
            payable = sumSalary.multiply(new BigDecimal(probationPeriodCoefficient)).multiply(new BigDecimal(actualAttendanceNumber / needAttendanceNumber)).add(perfectAttendanceAward).add(monthlyAssessmentRewards).add(backPay);
            //实发工资
            paidWages = payable.subtract(sumSocialSecurity).subtract(assessmentDeduction).subtract(attendanceDeduction).subtract(toolingDeduction);
        } else {
            //实际出勤天数，出勤天数之和
            actualAttendanceNumber = dayAttendanceNumber + nightAttendanceNumber + dayNightAttendanceNumber * 1;
            //长期工岗位补贴 补贴
            groupByDeptName.forEach((key, value) -> {
                sysDept.forEach(dept -> {
                    if (key.equals(dept.getDeptName()) && dayNightAttendanceNumber > 0) {
                        jobSubsidy = dept.getJobAllowance();
                        jobSalary = jobSalary.add(dept.getJobAllowance().multiply(new BigDecimal(value.size())));
                    }
                });
            });
            //全勤奖 通班大于13 ，不存在通班时 白 + 黑 - 2
            int daysOfMonth = DateUtils.getDaysOfMonth(new SimpleDateFormat(Constant.DATE_FORMAT_2).parse(workTime));
            if (dayNightAttendanceNumber > 0 && dayNightAttendanceNumber < 13) {
                perfectAttendanceAward = new BigDecimal(0);
            } else if (nightAttendanceNumber + dayAttendanceNumber < daysOfMonth - 2) {
                perfectAttendanceAward = new BigDecimal(0);
            } else {
                perfectAttendanceAward = new BigDecimal(150);
            }
            //考勤扣钱
            attendanceSalary(attendanceRecords);
            //应发工资 班次单价计算
            timeShiftList.forEach(timeShift -> {
                if (null != timeShift.getPrice()) {
                    BigDecimal price = new BigDecimal(timeShift.getPrice());
                    String name = timeShift.getName();
                    if ("白班".equals(name)) {
                        daySalary = new BigDecimal(dayAttendanceNumber).multiply(price);
                        //考勤扣款 = 班次价格 * 次数 + 次数 * 50
                        attendanceDeduction = attendanceDeduction.add(new BigDecimal(dayAbnormalAttendanceNumber).multiply(price)).add(new BigDecimal(50).multiply(new BigDecimal(dayAbnormalAttendanceNumber)));
                    }
                    if ("夜班".equals(name)) {
                        nightSalary = new BigDecimal(nightAttendanceNumber).multiply(price);
                        attendanceDeduction = attendanceDeduction.add(new BigDecimal(nightAbnormalAttendanceNumber).multiply(price)).add(new BigDecimal(50).multiply(new BigDecimal(nightAbnormalAttendanceNumber)));
                    }
                    if ("通班".equals(name)) {
                        dayNightSalary = new BigDecimal(dayNightAttendanceNumber).multiply(price);
                        attendanceDeduction = attendanceDeduction.add(new BigDecimal(dayNightAbnormalAttendanceNumber).multiply(price)).add(new BigDecimal(50).multiply(new BigDecimal(dayNightAbnormalAttendanceNumber)));
                    }
                }
            });
            payable = daySalary.add(nightSalary).add(dayNightSalary).add(perfectAttendanceAward).add(jobSubsidy).add(backPay);
            //实发工资
            paidWages = payable.subtract(attendanceDeduction).subtract(toolingDeduction);
        }
        return 1;
    }


    private void attendanceSalary(List<AttendanceDailyRecord> attendanceRecords) {
        Map<String, List<AttendanceDailyRecord>> groupByAbnormal = attendanceRecords.stream().collect(Collectors.groupingBy(AttendanceDailyRecord::getShiftName));
        groupByAbnormal.forEach((key, value) -> {
            int size = value.size();
            if ("白班".equals(key)) {
                dayAbnormalAttendanceNumber = size;
            }
            if ("夜班".equals(key)) {
                nightAbnormalAttendanceNumber = size;
            }
            if ("通班".equals(key)) {
                value.forEach(attendanceDailyRecord -> {
                    boolean firstFlag = 6 == attendanceDailyRecord.getFirstSignInResult() || 6 == attendanceDailyRecord.getFirstSignOutResult();
                    boolean secondFlag = 6 == attendanceDailyRecord.getSecondSignInResult() || 6 == attendanceDailyRecord.getSecondSignOutResult();
                    boolean thirdFlag = 6 == attendanceDailyRecord.getThirdSignInResult() || 6 == attendanceDailyRecord.getThirdSignOutResult();
                    boolean forthFlag = 6 == attendanceDailyRecord.getForthSignInResult() || 6 == attendanceDailyRecord.getForthSignOutResult();
                    if (firstFlag && secondFlag) {
                        dayAbnormalAttendanceNumber++;
                    } else if (firstFlag && secondFlag && thirdFlag) {
                        dayNightAbnormalAttendanceNumber++;
                    } else if (thirdFlag) {
                        nightAbnormalAttendanceNumber++;
                    }
                });
            }
        });
    }

    /**
     * 迟到 早退 扣款
     **/
    private int attendanceBeLate(List<AttendanceDailyRecord> attendanceRecords) {
        //普通迟到次数
        Integer normallyLate = 0;
        //一般迟到次数
        Integer usuallyLate = 0;
        //严重迟到次数
        Integer severelyLate = 0;
        //早退次数
        Integer leaveEarly = 0;
        /**数据统计,这里的代码为什么这么写 请咨询刘松山考勤组表是怎么设计的**/
        for (AttendanceDailyRecord attendanceRecord : attendanceRecords) {
            Integer firstSignInResult = attendanceRecord.getFirstSignInResult();
            Integer forthSignOutResult = attendanceRecord.getForthSignOutResult();
            Integer secondSignInResult = attendanceRecord.getSecondSignInResult();
            Integer thirdSignInResult = attendanceRecord.getThirdSignInResult();
            Integer thirdSignOutResult = attendanceRecord.getThirdSignOutResult();
            Integer forthSignInResult = attendanceRecord.getForthSignInResult();
            Integer firstSignOutResult = attendanceRecord.getFirstSignOutResult();
            switchCaseValue(firstSignInResult, normallyLate, usuallyLate, severelyLate, leaveEarly);
            switchCaseValue(forthSignOutResult, normallyLate, usuallyLate, severelyLate, leaveEarly);
            switchCaseValue(secondSignInResult, normallyLate, usuallyLate, severelyLate, leaveEarly);
            switchCaseValue(thirdSignInResult, normallyLate, usuallyLate, severelyLate, leaveEarly);
            switchCaseValue(thirdSignOutResult, normallyLate, usuallyLate, severelyLate, leaveEarly);
            switchCaseValue(forthSignInResult, normallyLate, usuallyLate, severelyLate, leaveEarly);
            switchCaseValue(firstSignOutResult, normallyLate, usuallyLate, severelyLate, leaveEarly);
        }
        //一般迟到 10元 普通迟到 20 严重迟到40 早退20 旷工50？
        return normallyLate * 10 + usuallyLate * 20 + severelyLate * 40 + leaveEarly * 20;
    }

    private void switchCaseValue(int value, Integer normallyLate, Integer usuallyLate, Integer severelyLate, Integer leaveEarly) {
        switch (value) {
            case 2:
                normallyLate++;
                break;
            case 3:
                usuallyLate++;
                break;
            case 4:
                severelyLate++;
                break;
            case 5:
                leaveEarly++;
                break;
            default:
                break;
        }
    }
}
